/*
 * Generates a set of 3-graphlets describing the user-generated portion of
 * the given program binary. 
 */
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <errno.h>
#include <assert.h>

#include <string>
#include <vector>

#include "InstructionDecoder.h"
#include "Instruction.h"

#include "CodeSource.h"
#include "CodeObject.h"
#include "Function.h"
#include "dyntypes.h"

#include "graphlet.h"
#include "colors.h"

using namespace std;
using namespace Dyninst;
using namespace Dyninst::ParseAPI;
using namespace Dyninst::InstructionAPI;
using namespace graphlets;

bool COLOR = true;

unsigned short node_color(Block * A)
{
    using namespace Dyninst::InstructionAPI;
    unsigned short ret = 0;
    
    CodeRegion * cr = A->region();
    const unsigned char* bufferBegin =
            (const unsigned char*)(cr->getPtrToInstruction(A->start()));
    if(!bufferBegin)
        return 0;

    InstructionDecoder dec(bufferBegin, A->end() - A->start(), cr->getArch());
    while(Instruction::Ptr insn = dec.decode()) {
        InsnColor::insn_color c = InsnColor::lookup(insn);    
        if(c != InsnColor::NOCOLOR) {
            assert(c <= 16);
            ret |= (1 << c); 
        }
    }
    return ret; 
}

// build edge type sets for A given B and C
node edge_sets(Block * A, Block * B, Block * C)
{
    multiset<int> ins;
    multiset<int> outs;
    multiset<int> selfs;
    unsigned short color = 0;

    Block::edgelist srcs = A->sources();
    Block::edgelist trgs = A->targets();
    
    Block::edgelist::iterator eit;

    for(eit=srcs.begin();eit != srcs.end(); ++eit) {
        if((*eit)->src() == B || (*eit)->src() == C)
            ins.insert((*eit)->type());
        else if((*eit)->src() == A)
            selfs.insert((*eit)->type());
    }
    for(eit=trgs.begin();eit != trgs.end(); ++eit) {
        if((*eit)->trg() == B || (*eit)->trg() == C)
            outs.insert((*eit)->type());
        // don't duplicate self edges
    }

    if(COLOR)
        color = node_color(A);

    return node(ins,outs,selfs,color);
}


